package ru.aslanov.schedule.server.gcalendar;

import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.XmlEventSource;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.util.ParseException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import ru.aslanov.schedule.model.*;
import ru.aslanov.schedule.utils.XMLUtil;

import javax.jdo.PersistenceManager;
import javax.servlet.ServletContext;
import javax.xml.datatype.DatatypeConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.io.InputStream;

/**
 * Created by IntelliJ IDEA.
 * Created: Mar 12, 2010 6:16:02 PM
 *
 * @author Sergey Aslanov
 */
public class GCalendarEventGenerator {
    private static final Document EMPTY_DOC;
    private Transformer eventTemplate;

    private static GCalendarEventGenerator instance;

    static {
        try {
            EMPTY_DOC = XMLUtil.DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().newDocument();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
    }


    public static GCalendarEventGenerator getInstance(ServletContext servletContext) {
        if (instance == null) {
            try {
                instance = new GCalendarEventGenerator(servletContext);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return instance;
    }

    private GCalendarEventGenerator(ServletContext servletContext) throws Exception {
        final InputStream stream = servletContext.getResourceAsStream("/WEB-INF/gcal-event-template.xsl");
        eventTemplate = TransformerFactory.newInstance().newTransformer(new StreamSource(stream));
    }


    private void setParam(String name, Object value) {
        if (value != null) {
            eventTemplate.setParameter(name, value);
        }
    }

    public CalendarEventEntry generateEvent(ScheduleItem scheduleItem, Group group, String defaultCity, PersistenceManager pm) throws TransformerException, IOException, ParseException {

        eventTemplate.clearParameters();
        setParam("group-title", group.getTitle());
        final Dance dance = group.getDance(pm);
        if (dance != null) {
            setParam("dance", dance.getName());
            setParam("dance-url", dance.getUrl());
        }
        final Level level = group.getLevel(pm);
        if (level != null) {
            setParam("level", level.getName());
            setParam("level-url", level.getUrl());
        }
        final Teacher teacher1 = group.getTeacher1(pm);
        if (teacher1 != null) {
            setParam("teacher1", teacher1.getName());
            setParam("teacher1-url", teacher1.getUrl());
        }
        final Teacher teacher2 = group.getTeacher2(pm);
        if (teacher2 != null) {
            setParam("teacher2", teacher2.getName());
            setParam("teacher2-url", teacher2.getUrl());
        }
        setParam("comment", group.getComment());
        setParam("welcome", group.getWelcome());
        if (group.getStarted() != null) {
            setParam("started", XMLUtil.date2XmlDate(group.getStarted(), DatatypeConstants.DATE).toXMLFormat());
        }

        Location location;
        if (scheduleItem.getLocationKey() != null) location = scheduleItem.getLocation(pm);
        else location = group.getLocation(pm);
        if (location != null) {
            String address = location.getAddress();
            if (address != null) {
                if (defaultCity != null && !address.startsWith(defaultCity)) {
                    address = defaultCity + ", " + address;
                }
                setParam("address", address);
            }
            setParam("metro", location.getMetro());
            setParam("location-descr", location.getComments());
        }

        String startTime = scheduleItem.getStartTime().replaceFirst(":", "");
        String endTime = scheduleItem.getEndTime().replaceFirst(":", "");

        String recurrance = "DTSTART;TZID=Europe/Moscow:20110601T" + startTime + "00\n" +
                "DTEND;TZID=Europe/Moscow:20110601T" + endTime + "00\n" +
                "RRULE:FREQ=WEEKLY;BYDAY=" + scheduleItem.getDayOfWeek().getGCalName() + ";WKST=MO";
        setParam("recurrance", recurrance);

        CalendarEventEntry entry = new CalendarEventEntry();

        final ExtensionProfile extensionProfile = new ExtensionProfile();
        entry.declareExtensions(extensionProfile);
        entry.parseAtom(extensionProfile, new XmlEventSource() {
            @Override
            public void parse(DefaultHandler handler) throws SAXException, IOException {
                try {
                    eventTemplate.transform(new DOMSource(EMPTY_DOC), new SAXResult(handler));
                } catch (TransformerException e) {
                    throw new SAXException(e);
                }
            }
        });

        BatchUtils.setBatchId(entry, scheduleItem.getEncodedKey());

        return entry;
    }
}
